#pragma once

#include <iostream>
#include <vector>
#include <queue>
#include <unistd.h>
#include "GardLock.hpp"
#include "Thread.hpp"
// 自动锁 + 单例模式
const int N = 5;

template <class T>
class ThreadPool
{
private:
    ThreadPool(int cap = N)
        : _cap(cap)
    {
        pthread_cond_init(&_cond, nullptr);
        pthread_mutex_init(&_mutex, nullptr);
    }

    ThreadPool(const ThreadPool<T>& th) = delete;
    void operator=(const ThreadPool<T>& th) = delete;
public:
    static ThreadPool<T>* get_instance()
    {
        if(pool == nullptr) // 防止线程安全
        {
            GardLock gardlock(&_mutex_init);
            if(pool == nullptr) // 提高效率
            {
                pool = new ThreadPool<T>;
                pool->init();
                pool->start();
            }
        }

        return pool;
    }

    pthread_mutex_t *getLock()
    {
        return &_mutex;
    }

    void threadWait()
    {
        pthread_cond_wait(&_cond, &_mutex);
    }

    void threadWakeup()
    {
        pthread_cond_signal(&_cond);
    }

    bool taskEmpty()
    {
        return tasks.empty();
    }

    T popTask()
    {
        T t = tasks.front();
        tasks.pop();
        return t;
    }

public:
    static void threadRoutine(void *args)
    {
        ThreadPool<T> *pool = static_cast<ThreadPool<T> *>(args);

        while (true)
        {
            T t;
            {
                GardLock gardlock(pool->getLock());
                while (pool->taskEmpty())
                {
                    pool->threadWait();
                }

                t = pool->popTask();
            }
            std::cout << " Get a message: " << t << std::endl;
            usleep(200);
        }
    }

    void init()
    {
        for (int i = 0; i < _cap; i++)
        {
            threads.push_back(thread(i, threadRoutine, this));
        }
    }

    void start()
    {
        for (auto &th : threads)
            th.run();
    }

    void PushTask(const T &in)
    {
        GardLock gardlock(&_mutex);

        tasks.push(in);
        threadWakeup();
    }

    ~ThreadPool()
    {
        for (auto th : threads)
            th.join();

        pthread_cond_destroy(&_cond);
        pthread_mutex_destroy(&_mutex);
    }

private:
    std::vector<thread> threads;

    std::queue<T> tasks;
    int _cap;

    pthread_cond_t _cond;
    pthread_mutex_t _mutex;

    static ThreadPool<T>* pool;
    static pthread_mutex_t _mutex_init;
};

template<class T>
ThreadPool<T>* ThreadPool<T>::pool = nullptr; 

template<class T>
pthread_mutex_t ThreadPool<T>::_mutex_init = PTHREAD_MUTEX_INITIALIZER;